/*=====================================================================
  This file is part of a Microsoft SQL Server Shared Source Application.
  Copyright (C) Microsoft Corporation.  All rights reserved.
 
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
======================================================= */

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.LoadTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LoaderPlugin
{
    /*
      This class is a sample LoadTest Plug-in class that loads data from an XML file and passes a row of
      data to each test that is started in the load test. The data is passed as context properties available
      in the TestContext of a unit test or a Web test.

      To use this class:

      1. Add the class to a test project.
      2. Build the test project.
      3. Hook this load test plugin up to your load test:
 
             In the load test editor, select the top-most node in the load test tree (this is the load test name).
             Go to the property sheet.  
             Click on the symbol next to the value for "Load Test Plug-in".
             Select the LoaderPlugin class as your plugin.
     
      4. Add a context parameter named "MaxTestIterations" to your load test:
         
            * Right-click the "Active Run Settings" node in the tree 
            * Select "Add Context Parameter" - you will see the property sheet 
            * For the parameter name, type "MaxTestIterations"
            * For the parameter value, specify the maximum number of tests to run
              
              Note that the duration specified for the load test still applies; the
              load test will stop when the time specified for the duration has expired
              even if the number of tests executed is less than "MaxTestIterations".
     
              If the number of test specified by "MaxTestIterations" has been completed,
              the load test will continue to run until the duration specified for the load 
              test is complete. So the "Tests / Sec" and "Requests / Sec" will drop to 0 
              for the remainder of the test. 
    */

    public class LoaderPlugin : ILoadTestPlugin
    {
        private LoadTest m_loadTest;

        // The name of the configuration file (including full path).
        private string m_configFileName;

        // member variables to record test iteration
        private int m_maxTestIterations;
        private int m_testsStarted;

        public LoaderPlugin()
        {            
        }

        public void Initialize(LoadTest loadTest)
        {
            try
            {
                // Save a reference to the LoadTest object
                m_loadTest = loadTest;

                // Register to listen to the TestStarting event
                m_loadTest.TestStarting += new EventHandler<TestStartingEventArgs>(TestStarting);

                // Initialize variables
                m_maxTestIterations = -1;
                m_testsStarted = 0;
                // We will honor MaxTestIterations if it's specified.
                if (m_loadTest.Context.ContainsKey("MaxTestIterations"))
                {
                    // Get value of MaxTestIterations
                    m_maxTestIterations = int.Parse((string)m_loadTest.Context["MaxTestIterations"]);

                    if (m_maxTestIterations <= 0)
                        throw new Exception("Please enter a number greater than 0 for MaxTestIterations.");
                }

                if (m_loadTest.Context.ContainsKey("ConfigFileName"))
                {
                    m_configFileName = (string)m_loadTest.Context["ConfigFileName"];
                }
                // Initialize the XmlDS class (this will read the XML file)
                XmlDS.Instance.Initialize(m_configFileName);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        // The TestStarting event handler will be called for each iteration of a test that is 
        // started within the load test
        private void TestStarting(object source, TestStartingEventArgs testStartingEventArgs)
        {
            try
            {
                // Get the next set of data and add each column to the context
                Dictionary<string, string> dictionary = XmlDS.Instance.GetNextRow();
                foreach (string key in dictionary.Keys)
                {
                    testStartingEventArgs.TestContextProperties.Add(key, dictionary[key]);
                }

                // Get run duration and pass as test context property. 
                testStartingEventArgs.TestContextProperties.Add("RunDuration", m_loadTest.RunSettings.RunDuration);

                // Is "MaxTestIteration" specified? 
                if (m_maxTestIterations > 0)
                {
                    int maxNum = 0;

                    // Note that if the load test is run on a test rig with more than one agent,
                    // the number of test iterations specified will be run on each of the agents.  
                    // Thus we adjust by dividing that number by the number of agents. 
                    if (m_loadTest.Context.AgentCount == 0)
                        maxNum = m_maxTestIterations;
                    else
                        maxNum = m_maxTestIterations / m_loadTest.Context.AgentCount;

                    if (++m_testsStarted == maxNum)
                    {
                        // Reset Load to 0. 
                        SetLoadForAllScenariosToZero();
                    }
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        private void SetLoadForAllScenariosToZero()
        {
            foreach (LoadTestScenario scenario in m_loadTest.Scenarios)
            {
                scenario.CurrentLoad = 0;
            }
        }
    }
}

